﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using SSM.DeepZoomViewer.Information;
using SSM.DeepZoomViewer.Utils;
using SSM.SmartMosaicUtils.Net;

namespace SSM.DeepZoomViewer
{
    /// <summary>
    /// ImageSelectedEventArgs
    /// </summary>
    public class ImageSelectedEventArgs : EventArgs
    {
        public string ImageUrl { get; set; }
    }

    /// <summary>
    /// DeepZoomViewerControl
    /// </summary>
    public partial class DeepZoomViewerControl : UserControl
    {
        public event EventHandler<ImageSelectedEventArgs> ImageSelected;
        public event EventHandler ThumbnailLoaded;

        delegate void NoArgumentDelegate();

        /// <summary>
        /// DeepZoomViewer에 보이는 이미지의 변경이 발생하는 경우 호출되는 이벤트
        /// </summary>
        public event EventHandler DeepZoomImageChanged;

        private DeepZoomInformation deepZoomInformation;

        private Bitmap bufferedImage;

        private IList<Level> levels;

        private bool isLoaded = false;

        private double DEFAULT_WIDTH_PER_SCALED_ZOOM_FACTOR;

        // ClientRectangle의 가로, 세로 비율
        private double clientRectangleRatio;

        private double zoomFactorNavigatorRatio;

        private Rectangle srcRect;
        public Rectangle SrcRect
        {
            get
            {
                return srcRect;
            }

            set
            {
                
                srcRect = value;
            }
        }

        private IList<double> zoomFactorOfLevel;

        private bool isMouseDown;

        private int oldX;
        private int oldY;

        private IList<string> viewedTiles = new List<string>();

        /// <summary>
        /// Thumbnail Bitmap
        /// </summary>
        public Bitmap Thumbnail
        {
            get;
            set;
        }

        /// <summary>
        /// ScaledZoomFactor Property
        /// </summary>
        private int scaledZoomFactor;
        private int ScaledZoomFactor
        {
            get
            {
                return scaledZoomFactor;
            }

            set
            {
                scaledZoomFactor = value;

                // ScaledZoomFactor 갱신
                if (scaledZoomFactor != 0)
                    DEFAULT_WIDTH_PER_SCALED_ZOOM_FACTOR =
                        (double)DeepZoomViewerConstants.DEFAULT_WIDTH / scaledZoomFactor;
                else
                    DEFAULT_WIDTH_PER_SCALED_ZOOM_FACTOR = 0;
            }
        }

        /// <summary>
        /// 현재 DeepZoom 이미지의 세션 ID
        /// </summary>
        public string SessionID
        {
            get;
            private set;
        }

        /// <summary>
        /// Image의 X좌표
        /// </summary>
        private int viewportX;
        public int ViewportX
        {
            get
            {
                return viewportX;
            }

            set
            {
                srcRect.X = viewportX;

                viewportX = value;
            }
        }

        /// <summary>
        /// Image의 Y좌표
        /// </summary>
        private int viewportY;
        public int ViewportY
        {
            get
            {
                return viewportY;
            }

            set
            {
                srcRect.Y = viewportY;

                viewportY = value;
            }
        }

        /// <summary>
        /// Image의 scale을 반영한 X좌표
        /// </summary>
        private int scaledViewportX;
        public int ScaledViewportX
        {
            get
            {
                return scaledViewportX;
            }

            set
            {
                scaledViewportX = value;
            }
        }

        /// <summary>
        /// Image의 scale을 반영한 Y좌표
        /// </summary>
        private int scaledViewportY;
        public int ScaledViewportY
        {
            get
            {
                return scaledViewportY;
            }

            set
            {
                scaledViewportY = value;
            }
        }

        /// <summary>
        /// 현재 가리키는 레벨
        /// </summary>
        private int currentLevel;
        public int CurrentLevel
        {
            get
            {
                return currentLevel;
            }

            set
            {
                currentLevel = value;
            }
        }

        /// <summary>
        /// 생성자
        /// </summary>
        public DeepZoomViewerControl()
        {
            InitializeComponent();

            this.Resize += new EventHandler(DeepZoomViewerControl_Resize);
            this.DoubleClick += new EventHandler(DeepZoomViewerControl_DoubleClick);
            this.MouseDown += new MouseEventHandler(DeepZoomViewerControl_MouseDown);
            this.MouseUp += new MouseEventHandler(DeepZoomViewerControl_MouseUp);
            this.MouseMove += new MouseEventHandler(DeepZoomViewerControl_MouseMove);
        }

        /// <summary>
        /// 더블 클릭됐을때 사진에대한 인덱스를 찾습니다.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DeepZoomViewerControl_DoubleClick(object sender, EventArgs e)
        {   
            Point? point = GetSubTilePoint(currentLevel, MousePosition.X, MousePosition.Y);

            if (point.HasValue)
            {
                TileSearcher searcher = new TileSearcher();

                string tileUrl = 
                    searcher.FindTileUrl
                    (
                        Convert.ToInt32(DeepZoomUrl.Substring(DeepZoomUrl.Length - 1, 1)),
                        point.Value.X, point.Value.Y
                    );

                if (ImageSelected != null)
                {
                    ImageSelectedEventArgs args = new ImageSelectedEventArgs();

                    args.ImageUrl = tileUrl;

                    ImageSelected(this, args);
                }
            }
        }

        /// <summary>
        /// Viewer가 Resize될때 필요한 작업을 수행한다.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DeepZoomViewerControl_Resize(object sender, EventArgs e)
        {
            // 메모리 낭비를 막기위해 만약 기존의 BufferedImage가 존재하면
            // 메모리에서 제거한다.
            if (bufferedImage != null)
                bufferedImage.Dispose();

            bufferedImage = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);

            clientRectangleRatio =
                (double)ClientRectangle.Height / ClientRectangle.Width;
        }

        /// <summary>
        /// Drag 구현을 위한 이벤트 핸들러
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DeepZoomViewerControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (isMouseDown)
            {
                ScaledViewportX += oldX - e.X;
                ScaledViewportY += oldY - e.Y;

                ViewportX =
                    Convert.ToInt32(ScaledViewportX * DEFAULT_WIDTH_PER_SCALED_ZOOM_FACTOR);
                ViewportY =
                    Convert.ToInt32(ScaledViewportY * DEFAULT_WIDTH_PER_SCALED_ZOOM_FACTOR);

                oldX = e.X;
                oldY = e.Y;

                Invalidate();
            }
        }

        /// <summary>
        /// Drag 구현을 위한 이벤트 핸들러
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DeepZoomViewerControl_MouseUp(object sender, MouseEventArgs e)
        {
            if (isMouseDown)
                isMouseDown = false;
        }

        /// <summary>
        /// Drag 구현을 위한 이벤트 핸들러
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DeepZoomViewerControl_MouseDown(object sender, MouseEventArgs e)
        {
            isMouseDown = true;

            oldX = e.X;
            oldY = e.Y;
        }

        /// <summary>
        /// 딥줌 정보가 있는 xml의 url
        /// </summary>
        private string deepZoomUrl;
        public string DeepZoomUrl
        {
            get
            {
                return deepZoomUrl;
            }

            set
            {
                // 기존에 정보가 존재했다면 여기서 정리한다.
                if (deepZoomUrl != null)
                    DestoryPrevDeepZoomInformation();

                deepZoomUrl = value;

                if (value != null)
                {
                    Uri deepZoomInformationUrl =
                        new Uri(value + DeepZoomViewerConstants.DEEPZOOM_INFORMATION_SUB_URL, UriKind.Absolute);

                    // 새로운 세션 아이디를 할당 받고, 이에 해당하는 디렉토리를 생성한다.
                    SessionID = Guid.NewGuid().ToString();
                    Directory.CreateDirectory(DeepZoomViewerConstants.TMP_PATH + "\\" + SessionID);

                    // 새로운 정보를 담기위해 List를 초기화한다.
                    // 성능 향상을 위해 초기에 크기를 잡아준다.
                    levels = new List<Level>(
                            DeepZoomViewerConstants.MAX_LEVEL - DeepZoomViewerConstants.MIN_LEVEL
                        );

                    // DeepZoom 정보를 다운로드하기 위해 Manager를 생성한다.
                    DeepZoomInformationManager informationManager = new DeepZoomInformationManager();
                    informationManager.Completed += new EventHandler<CompletedEventArgs>(InformationManagerCompleted);

                    // DeepZoom 정보의 다운로드를 시작한다.
                    informationManager.DownloadDeepZoomInformation(deepZoomInformationUrl);

                    // Thumbnail을 다운로드 받는다.
                    string thumbnailFilePath =
                        DeepZoomViewerConstants.TMP_PATH +
                        "\\" + SessionID + "\\"
                        + DeepZoomViewerConstants.DEEPZOOM_THUMBNAIL_FILENAME;

                    FileDownloader filedownloader = new FileDownloader();
                    filedownloader.DownloadFile(
                        value + DeepZoomViewerConstants.DEEPZOOM_THUMBNAIL_URL,
                        thumbnailFilePath);

                    Thumbnail = new Bitmap(thumbnailFilePath);

                    if (ThumbnailLoaded != null)
                        ThumbnailLoaded(this, null);
                }
                else
                {
                    // DeepZoom 이미지가 변경된 것을 알린다.
                    if (DeepZoomImageChanged != null)
                        DeepZoomImageChanged(this, null);
                }
            }
        }

        /// <summary>
        /// InformationManager가 DeepZoom 정보의 다운로드를 완료할 경우 호출되는 메서드
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void InformationManagerCompleted(object sender, CompletedEventArgs e)
        {
            DeepZoomInformationManager informationManager =
                (DeepZoomInformationManager)sender;

            deepZoomInformation = e.DeepZoomInformation;

            for (int levelIndex = DeepZoomViewerConstants.MIN_LEVEL; levelIndex <= DeepZoomViewerConstants.MAX_LEVEL; levelIndex++)
            {
                int levelWidth =
                    (int)Math.Round(deepZoomInformation.Width / Math.Pow(2, DeepZoomViewerConstants.MAX_LEVEL - levelIndex));
                int levelHeight =
                    (int)Math.Round(deepZoomInformation.Height / Math.Pow(2, DeepZoomViewerConstants.MAX_LEVEL - levelIndex));

                int horizontalTileCount = 0;
                int verticalTileCount = 0;

                // Horizontal의 tile 개수를 구한다.
                if (levelWidth <= deepZoomInformation.TileSize)
                    horizontalTileCount = 1;
                else
                    horizontalTileCount =
                        (int)Math.Ceiling((double)levelWidth / deepZoomInformation.TileSize);

                // Vertical의 tile 개수를 구한다.
                if (levelHeight <= deepZoomInformation.TileSize)
                    verticalTileCount = 1;
                else
                    verticalTileCount =
                        (int)Math.Ceiling((double)levelHeight / deepZoomInformation.TileSize);

                // 현재 레벨의 정보를 생성한다.
                Level level =
                    new Level(
                        SessionID,
                        levelIndex,
                        levelWidth,
                        levelHeight,
                        horizontalTileCount,
                        verticalTileCount,
                        DeepZoomUrl
                        );

                // Tile이 로드됐을때 처리하는 이벤트 핸들러를 세팅한다.
                level.TileImageLoaded += new EventHandler(LevelTileImageLoaded);

                levels.Add(level);
            }

            // 더이상 사용하지 않을 것이기에 이벤트 핸들러 삭제
            informationManager.Completed -=
                new EventHandler<CompletedEventArgs>(InformationManagerCompleted);

            isLoaded = true;

            // Cross thread 문제를 해결하기 위해 사용
            Invoke(new NoArgumentDelegate(ZoomFactorInit), null);

            // DeepZoom 이미지가 변경된 것을 알린다.
            if (DeepZoomImageChanged != null)
                DeepZoomImageChanged(this, null);
        }

        /// <summary>
        /// 기존에 존재하던 정보를 정리한다.
        /// </summary>
        private void DestoryPrevDeepZoomInformation()
        {
            // 로드 상태를 취소로 돌린다.
            isLoaded = false;

            // 각 레벨의 정보를 삭제한다.
            foreach (Level level in levels)
                // TileImageLoaded 이벤트 핸들러 삭제
                level.TileImageLoaded
                    -= new EventHandler(LevelTileImageLoaded);

            // Level 정보를 삭제한다.
            levels = null;

            // ZoomFactor 정보 삭제
            zoomFactorOfLevel.Clear();
            zoomFactorOfLevel = null;

            // 디렉토리를 삭제한다.
            string sessionDirect =
                DeepZoomViewerConstants.TMP_PATH + "\\" + SessionID;

            Directory.Delete(sessionDirect);
        }

        /// <summary>
        /// Level의 Tile로드가 완료된 경우 화면을 다시 그린다.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LevelTileImageLoaded(object sender, EventArgs e)
        {
            try
            {
                // Cross thread 문제를 해결하기 위해 Invoke를 사용한다.
                this.Invoke(
                    new NoArgumentDelegate(
                        Invalidate
                    )
                );
            }
            catch (ObjectDisposedException ex)
            { }
        }

        /// <summary>
        /// ZoomFactor 초기화
        /// </summary>
        private void ZoomFactorInit()
        {
            zoomFactorOfLevel = new List<double>();

            // 각 레벨에 해당하는 ZoomFactor를 구한다.
            //zoomFactorOfLevel
            foreach (Level level in levels)
            {
                double levelZoomFactor =
                    (level.Width * DeepZoomViewerConstants.DEFAULT_WIDTH) / (double)ClientRectangle.Width;

                zoomFactorOfLevel.Add(levelZoomFactor);
            }

            ZoomFactor = zoomFactorOfLevel[9];
        }

        /// <summary>
        /// Zoom 비율
        /// </summary>
        private double zoomFactor;
        public double ZoomFactor
        {
            get
            {
                return zoomFactor;
            }

            set
            {
                // ZoomFactor가 2의 배수승으로 올라갈때마다
                // 새로운 Level의 TileMap을 화면에 출력한다.
                zoomFactor = value;

                // ScaledZoomFacotr 갱신
                ScaledZoomFactor =
                    Convert.ToInt32(zoomFactor * ClientRectangle.Width) >> DeepZoomViewerConstants.NAVIGATOR_WIDTH_SHIFT_VALUE;

                ScaledViewportX =
                    (viewportX * scaledZoomFactor) / DeepZoomViewerConstants.DEFAULT_WIDTH;

                ScaledViewportY =
                    (viewportY * scaledZoomFactor) / DeepZoomViewerConstants.DEFAULT_WIDTH;

                // Viewport를 갱신한다.
                ViewportX =
                    Convert.ToInt32(ScaledViewportX * DEFAULT_WIDTH_PER_SCALED_ZOOM_FACTOR);

                ViewportY =
                    Convert.ToInt32(ScaledViewportY * DEFAULT_WIDTH_PER_SCALED_ZOOM_FACTOR);

                zoomFactorNavigatorRatio =
                    (double)ZoomFactor / DeepZoomViewerConstants.NAVIGATOR_WIDTH;

                if (zoomFactorNavigatorRatio != 0)
                {
                    srcRect = new Rectangle(
                        viewportX,

                        viewportY,

                        Convert.ToInt32(
                            DeepZoomViewerConstants.NAVIGATOR_WIDTH / 
                            zoomFactorNavigatorRatio),

                        Convert.ToInt32(
                            DeepZoomViewerConstants.NAVIGATOR_WIDTH / 
                            zoomFactorNavigatorRatio * clientRectangleRatio)
                        );
                }

                // 새로운 레벨을 구한다.
                CurrentLevel = GetLevelByScaledZoomFactor(ScaledZoomFactor);

                Invalidate();
            }
        }

        /// <summary>
        /// ScaledZoomFactor를 이용해 Level을 구한다.
        /// </summary>
        /// <param name="scaledZoomFactor"></param>
        /// <returns></returns>
        public int GetLevelByScaledZoomFactor(int scaledZoomFactor)
        {
            int level = 1;

            while (true)
            {
                if ((ScaledZoomFactor >> level) == 0)
                    break;
                else
                    level++;
            }

            return level - 1;
        }

        /// <summary>
        /// 컨트롤에서 사용한 임시 정보들을 삭제한다.
        /// </summary>
        public void Cleanup()
        {
            System.Threading.Thread thread = new System.Threading.Thread(DeleteFiles);
            thread.Start();
        }

        public void DeleteFiles()
        {
            // 디렉토리를 삭제한다.
            string sessionDirect =
                DeepZoomViewerConstants.TMP_PATH + "\\" + SessionID;

            if (SessionID != null)
            {
                while (true)
                {
                    try
                    {
                        System.Threading.Thread.Sleep(5000);

                        Directory.Delete(sessionDirect, true);

                        break;
                    }
                    catch (IOException ex)
                    {
                    }
                }
            }
        }

        /// <summary>
        /// Paint 메서드가 들어올 경우 처리
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics graphics = Graphics.FromImage(bufferedImage);

            graphics.Clear(Color.White);

            // 아직 로드 되지 않았거나 ZoomFactor가 0이면 화면을 그리지 않는다.
            if (isLoaded == false || ZoomFactor == 0)
            {
                e.Graphics.DrawImage(bufferedImage, 0, 0);

                return;
            }

            // x 좌표 구함
            int left = viewportX;

            if (left < 0)
                left = 0;

            // y 좌표 구함
            int top = viewportY;

            if (top < 0)
                top = 0;

            int right = srcRect.Right;

            if (right > DeepZoomViewerConstants.DEFAULT_WIDTH)
                right = DeepZoomViewerConstants.DEFAULT_WIDTH;

            int bottom = srcRect.Bottom;

            if (bottom > DeepZoomViewerConstants.DEFAULT_HEIGHT)
                bottom = DeepZoomViewerConstants.DEFAULT_HEIGHT;

            IList<string> newList = new List<string>();

            for (int tmpLevel = currentLevel; tmpLevel > 8; tmpLevel--)
            {
                Point[] tilePoint2 = GetTileIndex(
                    tmpLevel,
                    Convert.ToInt32(left * ((double)levels[tmpLevel].Width / DeepZoomViewerConstants.DEFAULT_WIDTH)),
                    Convert.ToInt32(top * ((double)levels[tmpLevel].Width / DeepZoomViewerConstants.DEFAULT_WIDTH)),
                    Convert.ToInt32(right * ((double)levels[tmpLevel].Width / DeepZoomViewerConstants.DEFAULT_WIDTH)),
                    Convert.ToInt32(bottom * ((double)levels[tmpLevel].Width / DeepZoomViewerConstants.DEFAULT_WIDTH))
                    );

                for (int horizontal = tilePoint2[0].X; horizontal <= tilePoint2[1].X; horizontal++)
                {
                    for (int vertical = tilePoint2[0].Y; vertical <= tilePoint2[1].Y; vertical++)
                    {
                        string value = tmpLevel + "," + horizontal + "," + vertical;
                        newList.Add(value);
                    }
                }
            }

            foreach (string value in newList)
            {
                // 이미 있다..
                if (viewedTiles.Contains(value))
                {
                    // 아무것도 하지 않는다.
                    viewedTiles.Remove(value);
                }
                // 없다. ( 새로운 것 )
                else
                {
                }
            }

            // 남아있는 것들은 메모리에서 제거한다.
            foreach (string value in viewedTiles)
            {
                string[] tokens = value.Split(',');

                int level = Convert.ToInt32(tokens[0]);
                int wTile = Convert.ToInt32(tokens[1]);
                int hTile = Convert.ToInt32(tokens[2]);

                levels[level].UnloadTile(wTile, hTile);
            }

            // 교체한다.
            viewedTiles = newList;

            Point[] tilePoint = GetTileIndex(
                currentLevel,
                Convert.ToInt32(left * ((double)levels[currentLevel].Width / DeepZoomViewerConstants.DEFAULT_WIDTH)),
                Convert.ToInt32(top * ((double)levels[currentLevel].Width / DeepZoomViewerConstants.DEFAULT_WIDTH)),
                Convert.ToInt32(right * ((double)levels[currentLevel].Width / DeepZoomViewerConstants.DEFAULT_WIDTH)),
                Convert.ToInt32(bottom * ((double)levels[currentLevel].Width / DeepZoomViewerConstants.DEFAULT_WIDTH))
                );

            double delta = (double)scaledZoomFactor / levels[currentLevel].Width;

            int myextendedX = Convert.ToInt32(scaledViewportX - tilePoint[0].X * deepZoomInformation.TileSize * delta);
            int myextendedY = Convert.ToInt32(scaledViewportY - tilePoint[0].Y * deepZoomInformation.TileSize * delta);

            // 타일을 비동기로 요청해야한다.. ( 낮은 레벨 부터 순서대로.. )
            int horizontalCount = 0;

            for (int horizontal = tilePoint[0].X; horizontal <= tilePoint[1].X; horizontal++)
            {
                int verticalCount = 0;

                for (int vertical = tilePoint[0].Y; vertical <= tilePoint[1].Y; vertical++)
                {
                    // 소스 크기
                    Rectangle subTileSrcRect = new Rectangle(
                        0,
                        0,
                        deepZoomInformation.TileSize,
                        deepZoomInformation.TileSize
                        );

                    // 출력될 크기
                    Rectangle subTileDstRect = new Rectangle(
                        0,
                        0,
                        Convert.ToInt32(deepZoomInformation.TileSize * delta),
                        Convert.ToInt32(deepZoomInformation.TileSize * delta)
                        );

                    subTileDstRect.Location = new Point(
                        Convert.ToInt32((-myextendedX) + horizontalCount * deepZoomInformation.TileSize * delta),
                        Convert.ToInt32((-myextendedY) + verticalCount * deepZoomInformation.TileSize * delta)
                        );

                    // 여기서 타일의 상태 판단
                    if (levels[currentLevel].GetTileLoadState(horizontal, vertical) == LoadState.Loaded)
                    {
                        // 로드 되있다면 바로 메모리에서 가져오자.
                        graphics.DrawImage(
                            levels[currentLevel].LoadTileImage(horizontal, vertical),
                            subTileDstRect,
                            subTileSrcRect,
                            GraphicsUnit.Pixel
                            );
                    }
                    else if (levels[currentLevel].GetTileLoadState(horizontal, vertical) == LoadState.Loading)
                    {
                        graphics.FillRectangle(new SolidBrush(Color.Beige), subTileDstRect);
                    }
                    else if (levels[currentLevel].GetTileLoadState(horizontal, vertical) == LoadState.UnLoaded)
                    {
                        // 로드가 안된경우
                        levels[currentLevel].RequestTileASync(horizontal, vertical);
                    }

                    verticalCount++;
                }

                horizontalCount++;
            }

            e.Graphics.DrawImage(bufferedImage, 0, 0);
        }

        /// <summary>
        /// Background
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
        }

        /// <summary>
        /// 레벨 이동
        /// </summary>
        /// <param name="level"></param>
        public void MoveToLevel(int level)
        {
            ZoomFactor = zoomFactorOfLevel[level];
        }

        /// <summary>
        /// TileIndex를 구하는 메서드
        /// </summary>
        /// <param name="level"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="right"></param>
        /// <param name="bottom"></param>
        /// <returns></returns>
        protected Point[] GetTileIndex(int level, int left, int top, int right, int bottom)
        {
            Point leftTopPoint = new Point();
            Point rightBottomPoint = new Point();

            // 왼쪽 타일 구함
            leftTopPoint.X = left / deepZoomInformation.TileSize;

            // 위쪽 타일 구함
            leftTopPoint.Y = top / deepZoomInformation.TileSize;

            // 오른쪽 타일 구함
            rightBottomPoint.X = right / deepZoomInformation.TileSize;
            if (rightBottomPoint.X == levels[level].HorizontalTileCount)
                rightBottomPoint.X -= 1;

            // 아래쪽 타일 구함
            rightBottomPoint.Y = bottom / deepZoomInformation.TileSize;
            if (rightBottomPoint.Y == levels[level].VerticalTileCount)
                rightBottomPoint.Y -= 1;

            return new Point[] { leftTopPoint, rightBottomPoint };
        }

        /// <summary>
        /// TileIndex를 구하는 메서드
        /// </summary>
        /// <param name="level"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="right"></param>
        /// <param name="bottom"></param>
        /// <returns></returns>
        protected Point GetTilePoint(int level, int x, int y)
        {
            Point leftTopPoint = new Point();

            // 왼쪽 타일 구함
            leftTopPoint.X = x / deepZoomInformation.TileSize;

            // 위쪽 타일 구함
            leftTopPoint.Y = y / deepZoomInformation.TileSize;

            int deltaX = x - (leftTopPoint.X * deepZoomInformation.TileSize);
            int deltaY = y - (leftTopPoint.Y * deepZoomInformation.TileSize);

            if (ScaledViewportX < 0)
            {
                deltaX += ScaledViewportX;
            }

            if (ScaledViewportY < 0)
            {
                deltaY += ScaledViewportY;
            }

            int subX = x / 64; 
            int subY = y / 64;

            leftTopPoint.X = subX;
            leftTopPoint.Y = subY;

            System.Diagnostics.Debug.WriteLine("X: " + (subX) + " Y: " + (subY));

            return leftTopPoint;
        }

        protected Point? GetSubTilePoint(int level, int x, int y)
        {
            // x 좌표 구함
            int left = ScaledViewportX;

            //if (left < 0)
            //    left = 0;

            // y 좌표 구함
            int top = ScaledViewportY;

            //if (top < 0)
            //    top = 0;

            int newX = left + x;
            int newY = top + y;

            if (newX < 0 || newY < 0)
                return null;

            if (newX > 8192 || newY > 6144)
                return null;

            if (currentLevel != 13)
                return null;

            return GetTilePoint(level, newX, newY);
        }
    }
}